﻿using System;
using System.Collections.Generic;
using System.Linq;
using GCTrackableRace.Interfaces;
using GcTrackableRace.Entities;

namespace GcTrackableRace.ScoreCalculator.Rules
{
	public class SpecificCountriesVisitedRule: BaseRule, IRaceRule
	{
		public SpecificCountriesVisitedRule(string reportColumnName, string startDate, string endDate, string pointAllocation, string keywords,
			IGeocacheInfo geocacheInfo, ILocationInfoLookup locationInfoLookup)
			: base(reportColumnName, startDate, endDate, pointAllocation)
		{
			Keywords = keywords.Split(new[] { ';', '|' }, StringSplitOptions.RemoveEmptyEntries).Select(k => k.Trim()).ToList();

			GeocacheInfo = geocacheInfo;

			LocationInfoLookup = locationInfoLookup;
		}

		private ILocationInfoLookup LocationInfoLookup { get; set; }

		private IEnumerable<string> Keywords { get; set; }

		private IGeocacheInfo GeocacheInfo { get; set; }

		protected override void SetRuleName()
		{
			RuleName = "Specific Countries Visited Rule";
		}

		public override void Process(ITrackable trackable, IEnumerable<ITrackableLog> trackableLogs)
		{
			var allValidDroppedAndVisitedLogs = (
				from log in trackableLogs
				where (
					(
						log.LogType == LogType.DroppedOff
						||
						log.LogType == LogType.Visited
					)
					&&
					(
						log.Date >= StartDate
						&&
						log.Date <= EndDate
					)
				)
				select log)
				.OrderBy(logs => logs.Date)
				.ThenBy(logs => logs.LogId)
				.ToList();

			var validCountryVisits = new List<string>();

			foreach(var log in allValidDroppedAndVisitedLogs)
			{
				var country = LocationInfoLookup.GetCountryCodeUsingCoords(log.Latitude, log.Longitude);

				var found = Keywords.Any(w => w.ToLowerInvariant() == country.ToLowerInvariant());

				if(found && !validCountryVisits.Contains(country))
				{
					validCountryVisits.Add(country);
				}
			}

			trackable.AddScore(new RuleScore(
				RuleName,
				ReportColumnName,
				validCountryVisits.Count,
				(int)(validCountryVisits.Count * PointAllocation),
				String.Join("|", validCountryVisits).Trim('|')));
		}
	}
}
